<template>
  <el-popover ref="popover" v-model="visible" popper-class="el-tree-select" placement="bottom-start" trigger="manual" @hide="hidePopover">
    <template v-if="!data.length && emptyText">
      <p class="el-select-dropdown__empty">{{ emptyText }}</p>
    </template>
    <el-scrollbar v-else
      tag="ul"
      wrap-class="el-select-dropdown__wrap"
      view-class="el-select-dropdown__list"
      ref="scrollbar"
      v-show="data.length">
      <el-tree
        ref="tree"
        :data="data"
        :props="props"
        :node-key="nodeKey"
        :show-checkbox="multiple"
        :check-on-click-node="multiple"
        :default-expanded-keys="expandedKeys"
        :check-strictly="checkStrictly"
        :expand-on-click-node="false"
        :highlight-current="true"
        @check-change="handleCheckChange"
        @node-click="handleNodeClick">
      </el-tree>
      <slot></slot>
    </el-scrollbar>
    <el-select
      slot="reference"
      ref="select"
      class="tree-select"
      popper-class="tree-select-popper"
      :placeholder="placeholder"
      :size="size"
      :multiple="multiple"
      :collapse-tags="collapseTags"
      :clearable="clearable"
      v-model="selectedData"
      v-clickoutside="handleClose"
      @click.native="visible = !visible"
      @change="handleChange"
      @clear="handleClear"
      @remove-tag="handleRemoveTag">
      <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"></el-option>
    </el-select>
  </el-popover>
</template>

<script>
import clickoutside from './clickoutside'

export default {
  name: 'el-tree-select',
  directives: { clickoutside },
  props: {
    // 内容为空的时候展示的文本
    emptyText: {
      type: String,
      default () {
        return '暂无数据'
      }
    },
    // 树结构展示数据
    data: {
      type: Array,
      default () {
        return []
      }
    },
    // 配置选项
    props: {
      type: Object,
      default () {
        return {}
      }
    },
    // 每个树节点用来作为唯一标识的属性
    nodeKey: {
      type: String,
      default () {
        return 'id'
      }
    },
    // 默认展开的节点 key 数组
    defaultExpandedKeys: {
      type: Array,
      default () {
        return []
      }
    },
    // 显示复选框情况下，是否严格遵循父子不互相关联
    checkStrictly: {
      type: Boolean,
      default () {
        return false
      }
    },
    // 占位符
    placeholder: {
      type: String,
      default () {
        return '请选择'
      }
    },
    // 输入框尺寸
    size: {
      type: String,
      default () {
        return 'small'
      }
    },
    // 配置是否可多选
    multiple: {
      type: Boolean,
      default () {
        return false
      }
    },
    // 配置多选时是否将选中值按文字的形式展示
    collapseTags: {
      type: Boolean,
      default () {
        return false
      }
    },
    // 配置是否可清空选择
    clearable: {
      type: Boolean,
      default () {
        return false
      }
    },
    // 绑定值
    value: {
      required: true
    }
  },
  data () {
    return {
      visible: false, // 是否显示树状选择器
      expandedKeys: [], // 默认展开的节点的 key 的数组
      checkedIds: [], // 所有被选中的节点的 key 所组成的数组数据
      checkedData: [], // 所有被选中的节点所组成的数组数据
      selectedData: null, // 选中的节点
      options: []
    }
  },
  computed: {
    checkedKeys () {
      if (!this.value) return []
      if (this.multiple) {
        return this.value
      }
      return [this.value]
    }
  },
  watch: {
    visible (val) {
      if (!val) {
        this.$refs.tree && this.$refs.tree.store._getAllNodes().forEach(item => item.expanded = false)
        return
      };
      this.renderWidth()
      this.initExpandedData()
      this.initCheckedData(this.checkedKeys)
    },
    checkedKeys () {
      this.initCheckedData()
    },
    selectedData (val) {
      this.$emit('input', val)
    }
  },
  mounted () {
    this.initExpandedData()
    this.initCheckedData(true)

    const that = this
    that.renderWidth()

    window.onresize = () => {
      that.renderWidth()
    }

    $('input').focus((e) => {
      let isCurr = e.currentTarget.parentElement.parentElement.className.indexOf('tree-select') == 10
      !isCurr && that.$refs.tree && !that.$refs.tree.$el.contains(e.target) && (that.visible = false)
    })
  },
  methods: {
    /**
     * 设置展开的节点
     */
    initExpandedData () {
      if (!this.$refs.tree) {
        return
      }
      this.$refs.tree.store._getAllNodes().forEach(item => item.expanded = false)
      this.expandedKeys = Object.assign([], this.defaultExpandedKeys)
      if (!this.checkedKeys || !this.checkedKeys.length) {
        return
      }
      if (!this.multiple) {
        var node = this.$refs.tree.getNode(this.checkedKeys[0])
        node && this.expandedKeys.push(node.parent.key)
        return
      }
      Array.push.apply(this.expandedKeys, this.checkedKeys.map((item) => {
        var node = this.$refs.tree.getNode(item)
        if (node) return node.parent.key
      }))
    },
    /**
     * 设置勾选的节点
     */
    initCheckedData (isInitial) {
      if (!this.$refs.tree) {
        return
      }
      if (this.multiple) {
        if (this.checkedKeys && this.checkedKeys.length) {
          this.checkSelectedNodes(this.checkedKeys)
        } else {
          this.clearSelectedNodes(isInitial)
        }
        return
      }
      if (this.checkedKeys && this.checkedKeys.length) {
        this.checkSelectedNode(this.checkedKeys)
      } else {
        this.clearSelectedNode(isInitial)
      }
    },
    /**
     * 多选模式下勾选传进来的节点
     */
    checkSelectedNodes (checkedKeys) {
      this.$refs.tree.setCheckedKeys(checkedKeys)
    },
    /**
     * 单选模式下选中传进来的节点
     */
    checkSelectedNode (checkedKeys) {
      var item = checkedKeys[0]
      this.$refs.tree.setCurrentKey(item)
      var node = this.$refs.tree.getNode(item)
      this.setSelectOption(node)
    },
    /**
     * 单选模式下清空选中
     */
    clearSelectedNode (isInitial = false) {
      this.selectedData = ''
      this.$refs.tree.setCurrentKey(null)
      !isInitial && this.$emit('change', null)
    },
    /**
     * 单选模式下点击tree节点，设置select选项
     */
    setSelectOption (node) {
      this.options = []
      if (!node) {
        this.selectedData = ''
        return
      }
      this.options.push({
        value: node.key,
        label: node.label
      })
      this.selectedData = node.key
    },
    /**
     * 下拉框宽度自适应
     */
    renderWidth () {
      this.$nextTick(() => {
        let w
        this.$refs.select && (w = this.$refs.select.$el.getBoundingClientRect().width - 2)
        $('.el-tree-select .el-tree').css('min-width', `${w}px`)
        this.data.length && $('.el-tree-select').css('width', 'auto')
        !this.data.length && this.emptyText && $('.el-tree-select').css('width', `${w}px`)
      })
    },
    /**
     * 下拉框隐藏时触发
     */
    hidePopover () {
      if (!this.$refs.tree) {
        return this.$emit('hide', [], [])
      }
      if (this.multiple) {
        this.checkedIds = this.$refs.tree.getCheckedKeys()
        this.checkedData = this.$refs.tree.getCheckedNodes()
      } else {
        this.checkedIds = this.$refs.tree.getCurrentKey()
        this.checkedData = this.$refs.tree.getCurrentNode()
      }
      this.$emit('hide', this.checkedIds, this.checkedData)
    },
    /**
     * 节点选中状态发生变化时的回调
     */
    handleCheckChange () {
      var checkedKeys = this.$refs.tree.getCheckedKeys()
      var nodes = []
      this.options = checkedKeys.map((item) => {
        var node = this.$refs.tree.getNode(item)
        nodes.push(node)
        return {
          value: node.key,
          label: node.label
        }
      })
      this.selectedData = this.listToTree(nodes).map((node) => {
        return node.key
      })
      let nodeData = []
      this.selectedData.forEach((key) => { nodeData.push(this.$refs.tree.getNode(key)) })
      this.$emit('change', nodeData)
      setTimeout(() => { this.$refs.popover.updatePopper() }, 50)
    },
    /**
     * list转换为树结构
     */
    listToTree (list) {
      var map = {}
      for (var n of list) {
        map[n.key] = n
      }
      var nodes = []
      for (var d of list) {
        var p = map[d.parent.key]
        if (!p) {
          nodes.push(d)
          continue
        }
        p.children || (p.children = [])
        p.children.push(d)
      }
      return nodes
    },
    /**
     * 节点被点击时的回调
     */
    handleNodeClick (data, node) {
      if (this.multiple) return
      this.setSelectOption(node)
      this.visible = !this.visible
      this.$emit('change', this.$refs.tree.getNode(this.selectedData))
    },
    /**
     * 选中值发生变化时触发
     */
    handleChange (selectedData) {
      if (this.multiple && !selectedData.length) {
        this.clearSelectedNodes()
      }
      if (!this.multiple) {
        this.$emit('change', this.$refs.tree.getNode(this.selectedData))
        return
      }
      let nodeData = []
      this.selectedData.forEach((key) => { nodeData.push(this.$refs.tree.getNode(key)) })
      this.$emit('change', nodeData)
    },
    /**
     * 多选模式下清除所有勾选
     */
    clearSelectedNodes () {
      var checkedKeys = this.$refs.tree.getCheckedKeys()
      for (let i = 0; i < checkedKeys.length; i++) {
        this.$refs.tree.setChecked(checkedKeys[i], false)
      }
    },
    /**
     * 多选模式下移除tag时触发
     */
    handleRemoveTag (val) {
      this.$refs.tree.setChecked(val, false)
      var node = this.$refs.tree.getNode(val)
      if (!this.checkStrictly && node.childNodes.length) {
        this.treeToList(node).map(item => {
          !item.childNodes.length && this.$refs.tree.setChecked(item, false)
        })
        this.handleCheckChange()
      }
      let nodeData = []
      this.selectedData.forEach((key) => { nodeData.push(this.$refs.tree.getNode(key)) })
      this.$emit('change', nodeData)
    },
    /**
     * 树结构转换为list
     */
    treeToList (tree) {
      var queen = []
      var list = []
      queen = queen.concat(tree)
      while (queen.length) {
        var first = queen.shift()
        first.childNodes && (queen = queen.concat(first.childNodes))
        list.push(first)
      }
      return list
    },
    /**
     * 可清空模式下用户点击清空按钮时触发
     */
    handleClear () {
      this.handleClose()
      if (this.multiple) {
        this.clearSelectedNodes()
        return
      }
      this.clearSelectedNode()
    },
    /**
     * 关闭下拉框
     */
    handleClose () {
      this.visible = false
    }
  }
}
</script>

<style lang="less">
  .tree-select-popper {
    display: none;
  }
  .el-tree-select {
    padding: 0 !important;
    .popper__arrow {
      left: 35px !important;
    }
    .el-tree-node__content {
      height: 34px !important;
      line-height: 34px;
      padding-right: 10px;
    }
  }
  .vc-theme-default {
    .tree-node {
      color: #409EFF;
      font-weight: 400;
    }
    .el-tree-select {
      .is-current > .el-tree-node__content:first-child {
        .tree-node;
      }
    }
    .is-multiple + .el-tree-select .el-tree-node.is-checked {
      .tree-node;
    }
  }
  .vc-theme-green {
    .tree-node {
      color: #31C7B2;
      font-weight: 400;
    }
    .el-tree-select {
      .is-current > .el-tree-node__content:first-child {
        .tree-node;
      }
    }
    .is-multiple + .el-tree-select .el-tree-node.is-checked {
      .tree-node;
    }
  }
</style>
<style lang="less" scoped>
  span:first-child {
    width: 100% !important;
    display: inline-block;
    .tree-select {
      width: 100% !important;
    }
  }
</style>
